﻿unit utils;
//разный самописный стаф помогающий в работе

interface

type

  TRGBColor = record
    case Cardinal of
      1: (B, G, R, A: Byte;);
      2: (rgba: Cardinal;);
  end;

  THSVColor = record
    case Cardinal of
      1: (V, S, H: Byte;);
      2: (hsv: Cardinal;);
  end;

  //вычисляет быстрый квадратный корень
  function QSqrt(x: Single): Single;

  //форматирует строку без SysUtils
  //Аргументы: %d - Integer, %s - String, %f - Single, %% - '%'
  function Format(Input: string; args: array of const): string;

  //преобразовывает удобный HSV в неудобный, но нужный, RGB и обратно
  function HSVtoRGB(HSV: THSVColor): TRGBColor;
  function RGBtpHSV(RGB: TRGBColor): THSVColor;

  procedure zglQTimer_Start(FuncName: AnsiString);
  procedure zglQTimer_Stop();

//  function zglKeyPtr(Key: car): Pointer;

implementation

uses
  zglHeader;

var
  FName: AnsiString;
  QTStamp: Double;

function QSqrt(x: Single): Single;
const
  n = 7; { 7-8 достаточно }
var
  i: Integer;
begin
  Result := 0;
  if x <= 0 then
    Exit
  else
    Result := 4;
  for i := 0 to n do
    Result := (Result + x / Result) / 2;
end;

// Форматирование строк
// arg types %d - Decimal, %s - String, %f - float, %% - '%'
function Format(Input: string; args: array of const): string;
var
  s, ts: string;
  outS: string;
  posT: Integer;
  argInd: Integer;
  argMax: Integer;
  ind, indOut: Integer;
begin
  s := Input;
  outS := '';
  argInd := -1;
  argMax := Length(args) - 1;

  while Pos('%', s) <> 0 do
  begin
    inc(argInd);

    posT := Pos('%', s);
    outS := outS + Copy(s, 1, posT - 1);
    Delete(s, 1, posT);

    if Length(s) <= 0 then
      Break;

    case s[1] of
      's': outS := outS + args[argInd].VPWideChar;
      'd': begin
        Str(args[argInd].VInteger, ts);
        outS := outS + ts;
      end;
      'f': begin
        Str(args[argInd].VExtended^:8:2, ts);
        while (Length(ts) >= 1) and (ts[1] = #32) do
          Delete(ts, 1, 1);
        outS := outS + ts;
      end;
      '%': outS := outS + s[1];
      else
        outS := outS +  '[Unknown]'
    end;
    Delete(s, 1, 1);

  end;
  Result := outS + s;
end;

function HSVtoRGB(HSV: THSVColor): TRGBColor;
var
  //Реальные параметры HSV
  rH: Integer;
  rS: Double;
  rV: Byte;
  //Промежуточные значения
  Hi: Integer;
  f: Double;
  p, q, t: Byte;
begin
  rH := (HSV.H * 360) div $FF;   //(0..360)
  rS := HSV.S / $FF;             //(0..1)
  rV := HSV.V;                   //(0..255)

  Hi := (rH div 60) mod 6;
  f := rH / (60 - (rH div 60));
  p := Round(rV * (1 - rS));
  q := Round(rV * (1 - f * rS));
  t := Round(rV * (1 - (1 - f) * rS));

  case Hi of
    0: Result.rgba := (rV shl 16) or (t  shl 8) or  p;
    1: Result.rgba := ( q shl 16) or (rV shl 8) or  p;
    2: Result.rgba := ( p shl 16) or (rV shl 8) or  t;
    3: Result.rgba := ( p shl 16) or ( q shl 8) or rV;
    4: Result.rgba := ( t shl 16) or ( p shl 8) or rV;
    5: Result.rgba := (rV shl 16) or ( p shl 8) or  q;
  end;
end;

function MaxByte(V1: Byte; V2: Byte): Byte;
begin
  if V1 > V2 then
    Result := V1
  else
    Result := V2;
end;

function MinByte(V1: Byte; V2: Byte): Byte;
begin
  if V1 < V2 then
    Result := V1
  else
    Result := V2;
end;

function RGBtpHSV(RGB: TRGBColor): THSVColor;
var
  tMin: Byte;
  tH: Integer;
begin
  Result.V := MaxByte(RGB.R, RGB.G);
  Result.V := MaxByte(Result.V, RGB.B);
  tMin := MinByte(RGB.R, RGB.G);
  tMin := MinByte(tMin, RGB.B);

  if Result.V = 0 then
    Result.S := 0
  else
    Result.S := Round((1 - (tMin / Result.V)) * $FF);

  Result.H := 0;
  if (Result.V = RGB.R) and (RGB.G >= RGB.B) then
    Result.H := Round((60 * ((RGB.G - RGB.B) / (Result.V - tMin))      ) * $FF / 360);
  if (Result.V = RGB.r) and (RGB.G < RGB.B) then
    Result.H := Round((60 * ((RGB.G - RGB.B) / (Result.V - tMin)) + 360) * $FF / 360);
  if (Result.V = RGB.G) then
    Result.H := Round((60 * ((RGB.B - RGB.R) / (Result.V - tMin)) + 120) * $FF / 360);
  if (Result.V = RGB.B) then
    Result.H := Round((60 * ((RGB.R - RGB.G) / (Result.V - tMin)) + 240) * $FF / 360);

end;

procedure zglQTimer_Start(FuncName: AnsiString);
begin
  FName := FuncName;
  QTStamp := timer_GetTicks;
end;

procedure zglQTimer_Stop();
var
  dQT: Double;
begin
  dQT := timer_GetTicks - QTStamp;
  log_Add(FName + ': ' + u_FloatToStr(dQT, 4));
end;

end.
